package pers.mihao.quickstream.common.plus.jdbc.sequence;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author mihao
 * @since 2023/1/3
 */
@Slf4j
public abstract class AbstractSequence implements Sequence {

    protected static final int DEFAULT_INNER_STEP = 10;

    protected String sequenceKey;

    /**
     * 步长
     */
    protected int innerStep = DEFAULT_INNER_STEP;

    protected AtomicInteger atomicInteger = new AtomicInteger(-1);

    // 有效的最大序列值
    protected int maxRange;

    private final Lock lock = new ReentrantLock();

    @Override
    public int nextValue() {
        int value = atomicInteger.incrementAndGet();
        if (value <= maxRange) {
            return value;
        }
        tryFlushRange();
        return nextValue();
    }

    private void tryFlushRange() {
        try {
            lock.lock();
            if (atomicInteger.get() > maxRange) {
                setNewRangeValue();
            }
        } finally {
            lock.unlock();
        }
    }

    /**
     * 从数据库区取新的序列
     */
    protected void setNewRangeValue() {
        int currValue = getAndIncrementNewRange(sequenceKey, innerStep);
        maxRange = currValue + innerStep;
        atomicInteger.set(currValue);
        log.info("设置新的值 {} {}", currValue, maxRange);
    }

    protected abstract int getAndIncrementNewRange(String sequenceKey, int innerStep);
}
